package cn.uncode.springcloud.admin.controller.system;

import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import cn.uncode.cache.CacheUtils;
import cn.uncode.cache.framework.Level;
import cn.uncode.springcloud.starter.web.result.R;


@Controller
@RequestMapping("/cache")
public class CacheController {
	
	private Gson gson = new GsonBuilder().registerTypeAdapter(Timestamp.class,new TimestampTypeAdapter()).setDateFormat("yyyy-MM-dd HH:mm:ss").create();


    //打开路由列表
    @RequestMapping(value = "/list" , method = RequestMethod.GET)
    @ResponseBody
    public R<List<Map<String, Object>>> list(@RequestParam String storeRegion, 
    		@RequestParam int page, @RequestParam int limit){
    	List<Map<String, Object>> rtMap = new ArrayList<>();
    	Set<String> keys = CacheUtils.getCache().storeRegionKeys(storeRegion, Level.Remote);
    	if(keys != null) {
    		int start = (page-1)*limit;
    		int end = page*limit;
    		if(keys.size() < end) {
    			end = keys.size();
    		}
    		List<String> list = new ArrayList<>(keys);
    		while(start < end) {
    			String key = list.get(start);
    			Object value = CacheUtils.getCache(storeRegion).get(key, Level.Remote);
    			if(null != value) {
    				int ttl = CacheUtils.getCache(storeRegion).ttl(key, Level.Remote);
    				Map<String, Object> obj = new HashMap<>();
    				obj.put("id", key);
    				obj.put("key", key);
    				obj.put("value", gson.toJson(value));
    				obj.put("region", storeRegion);
    				obj.put("ttl", ttl);
    				rtMap.add(obj);
    			}
    			start++;
    		}
    		return R.success(rtMap).fill("count", keys.size());
    	}
        return R.success();
    }

    @RequestMapping(value = "/delete" , method = RequestMethod.GET)
    @ResponseBody
    public  R<Boolean> delete(@RequestParam String storeRegion, @RequestParam String ids){
    	if(StringUtils.isNotBlank(ids)) {
    		for(String id:ids.split(",")) {
    			if(StringUtils.isNotBlank(id)) {
    				CacheUtils.getCache(storeRegion).remove(id, Level.Remote);
    			}
    		}
        	return R.success();
    	}
        return R.failure();
    }
    
    
    @GetMapping("/regions")
    @ResponseBody
    public R<List<Map<String, Object>>> instances(){
    	List<Map<String, Object>> rtMap = new ArrayList<>();
    	Set<String> stores = CacheUtils.getCache().storeRegions(Level.Remote);
		if(null != stores) {
			for(String item : stores){
				Map<String, Object> obj = new HashMap<>();
				obj.put("name", item);
				rtMap.add(obj);
			}
		}
    	return R.success(rtMap);
    }
    
    @GetMapping("/test")
    @ResponseBody
    public R<Boolean> test(){
    	CacheUtils.getCache().put("test"+System.currentTimeMillis(), "hello word!");
    	return R.success();
    }
    
    @GetMapping("/query")
    @ResponseBody
    public R<List<Map<String, Object>>> query(@NonNull @RequestParam String pattern, 
    		@RequestParam int page, @RequestParam int limit){
    	List<Map<String, Object>> rtMap = new ArrayList<>();
    	Set<String> keys = CacheUtils.getRedisCache().keys(pattern);
    	if(keys != null) {
    		int start = (page-1)*limit;
    		int end = page*limit;
    		if(keys.size() < end) {
    			end = keys.size();
    		}
    		List<String> list = new ArrayList<>(keys);
    		while(start < end) {
    			String key = list.get(start);
    			Map<String, Object> obj = new HashMap<>();
				obj.put("id", key);
				obj.put("key", key);
    			rtMap.add(obj);
    			start++;
    		}
    		return R.success(rtMap).fill("count", keys.size());
    	}
    	return R.success();
    }
    
    @GetMapping("/del")
    @ResponseBody
    public R<Boolean> del(@NonNull @RequestParam String key){
    	long rt = CacheUtils.getRedisCache().del(key);
    	if(rt > 0) {
    		return R.success();
    	}
    	return R.failure();
    }
    
    class TimestampTypeAdapter implements JsonSerializer<Timestamp>, JsonDeserializer<Timestamp>{
	    public JsonElement serialize(Timestamp src, Type arg1, JsonSerializationContext arg2) {   
	    	DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   
	        String dateFormatAsString = format.format(new Date(src.getTime()));   
	        return new JsonPrimitive(dateFormatAsString);   
	    }   
	  
	    public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {   
	        if (!(json instanceof JsonPrimitive)) {   
	            throw new JsonParseException("The date should be a string value");   
	        }   
	  
	        try {   
	        	DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   
	            Date date = (Date) format.parse(json.getAsString());
	            return new Timestamp(date.getTime());
	        } catch (Exception e) {   
	            throw new JsonParseException(e);   
	        }   
	    }
	}
}
